package aftersale

import (
	"context"
	// "fmt"
	"strconv"
	"strings"

	"mall/common/globalkey"
	"mall/common/modelx"
	"mall/common/moneyx"
	"mall/common/utils/pointy"
	"mall/service/order/model"
	"mall/service/order/rpc/internal/svc"
	"mall/service/order/rpc/internal/utils/errorhandler"
	"mall/service/order/rpc/types/order"

	// "github.com/sirupsen/logrus"
	"github.com/zeromicro/go-zero/core/logx"
)

type BackendGetAfterSaleListLogic struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
	logx.Logger
}

func NewBackendGetAfterSaleListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *BackendGetAfterSaleListLogic {
	return &BackendGetAfterSaleListLogic{
		ctx:    ctx,
		svcCtx: svcCtx,
		Logger: logx.WithContext(ctx),
	}
}

func (l *BackendGetAfterSaleListLogic) BackendGetAfterSaleList(in *order.BackendAfterSaleListReq) (*order.BackendAfterSaleListResp, error) {
	// logrus.Info(fmt.Sprintf("BackendGetAfterSaleList: %+v", in))
	// Page:1  PageSize:10
	// logx.Infof("BackendGetAfterSaleList : %+v ", in)

	var orderBys []string
	if len(in.OrderBy) > 0 {
		for _, orderBy := range in.OrderBy {
			order := " ASC"
			if orderBy.Order == "1" {
				order = " DESC"
			}
			switch orderBy.Field {
			case "id":
				orderBys = append(orderBys, model.AfterSaleRequestColumns.ID+order)
			case "orderId":
				orderBys = append(orderBys, model.AfterSaleRequestColumns.OrderID+order)
			case "createdAt":
				orderBys = append(orderBys, model.AfterSaleRequestColumns.CreatedAt+order)
			}
		}
	}

	var stati string
	var requestType string
	if len(in.FilterBy) > 0 {
		for _, filterBy := range in.FilterBy {
			switch filterBy.Field {
			case "status":
				stati = filterBy.In
			case "type":
				requestType = filterBy.In
			}
		}
	}

	var page uint64
	var pageSize uint64
	var restricted bool
	var withCount int
	var preCount int64
	filterMap := make(map[string]map[string][]any)
	resp := &order.BackendAfterSaleListResp{}
	if in.UserId != nil && *in.UserId > 0 {
		filterMap[model.AfterSaleRequestColumns.UserID] = map[string][]any{
			"equalTo": {*in.UserId},
		}
	}
	if in.Ids != nil && len(*in.Ids) > 0 {
		if vals := modelx.UniqueInterfaces(*in.Ids, 64); len(vals) == 0 {
			return resp, nil
		} else {
			filterMap[model.AfterSaleRequestColumns.ID] = map[string][]any{
				"in": vals,
			}
			restricted = true
			withCount = -1
			preCount = int64(len(vals))
		}
	}

	var statusIsSet bool
	var isAll bool
	statusMap := make(map[string][]any)
	switch requestType {
	case "1": // 全部
		statusMap["notEqualTo"] = []any{
			globalkey.AfterSaleStatusClosed,
			globalkey.AfterSaleStatusTimeouted,
		}
		isAll = true
	case "2": // 已完成
		filterMap[model.AfterSaleRequestColumns.Status] = map[string][]any{
			"equalTo": {globalkey.AfterSaleStatusSuccess},
		}
		statusIsSet = true
	case "3": // 待审核
		filterMap[model.AfterSaleRequestColumns.Status] = map[string][]any{
			"equalTo": {globalkey.AfterSaleStatusPending},
		}
		statusIsSet = true
	case "4": // 待退货
		filterMap[model.AfterSaleRequestColumns.Status] = map[string][]any{
			"equalTo": {globalkey.AfterSaleStatusAwaitReturn},
		}
		statusIsSet = true
	case "5": // 待退款
		filterMap[model.AfterSaleRequestColumns.Status] = map[string][]any{
			"equalTo": {globalkey.AfterSaleStatusAwaitRefund},
		}
		statusIsSet = true
	case "6": // 待换货
		filterMap[model.AfterSaleRequestColumns.Status] = map[string][]any{
			"equalTo": {globalkey.AfterSaleStatusAwaitBarter},
		}
		statusIsSet = true
	case "7": // 已发货 待签收
		filterMap[model.AfterSaleRequestColumns.Status] = map[string][]any{
			"equalTo": {globalkey.AfterSaleStatusShipped},
		}
		statusIsSet = true
	case "8": // 已驳回
		filterMap[model.AfterSaleRequestColumns.Status] = map[string][]any{
			"equalTo": {globalkey.AfterSaleStatusRejected},
		}
		statusIsSet = true
	case "9": // 关闭或超时
		filterMap[model.AfterSaleRequestColumns.Status] = map[string][]any{
			"in": {
				globalkey.AfterSaleStatusClosed,
				globalkey.AfterSaleStatusTimeouted,
			},
		}
		statusIsSet = true
	}

	if !restricted {
		page = in.Page
		pageSize = in.PageSize
		withCount = 1
	}

	var startTimeIn []any
	var endTimeIn []any
	if in.StartTime != nil && len(strings.TrimSpace(*in.StartTime)) > 0 {
		if startTime, err := modelx.ParseLocalDate(strings.TrimSpace(*in.StartTime)); err == nil {
			startTimeIn = append(startTimeIn, startTime)
		}
	}
	if in.EndTime != nil && len(strings.TrimSpace(*in.EndTime)) > 0 {
		if endTime, err := modelx.ParseLocalDate(strings.TrimSpace(*in.EndTime)); err == nil {
			endTimeIn = append(endTimeIn, endTime)
		}
	}
	createdAtMap := make(map[string][]any)
	if len(startTimeIn) > 0 {
		createdAtMap["moreThanOrEqualTo"] = startTimeIn
	}
	if len(endTimeIn) > 0 {
		createdAtMap["lessThan"] = endTimeIn
	}
	filterMap[model.AfterSaleRequestColumns.CreatedAt] = createdAtMap

	if isAll {
		ret, _, err := l.svcCtx.AfterSaleRequest.GetList(l.ctx, model.M{
			"statistic": "1",
		}, 5, filterMap)
		if err != nil {
			// return nil, errorhandler.DefaultRepositoryError(l.Logger, err, in)
			logx.Errorw("BackendGetAfterSaleList statistic err", logx.Field("detail", err.Error()))
		} else if len(ret) > 0 {
			statusStatisticMap := make(map[uint32]uint32)
			var total uint64
			for _, v := range ret {
				switch uint32(v.Status) {
				case globalkey.AfterSaleStatusSuccess:
					statusStatisticMap[2] += uint32(v.OrderID)
				case globalkey.AfterSaleStatusPending:
					statusStatisticMap[3] += uint32(v.OrderID)
				case globalkey.AfterSaleStatusAwaitReturn:
					statusStatisticMap[4] += uint32(v.OrderID)
				case globalkey.AfterSaleStatusAwaitConfirm:
					statusStatisticMap[5] += uint32(v.OrderID)
				case globalkey.AfterSaleStatusAwaitRefund:
					statusStatisticMap[6] += uint32(v.OrderID)
				case globalkey.AfterSaleStatusAwaitBarter:
					statusStatisticMap[7] += uint32(v.OrderID)
				case globalkey.AfterSaleStatusShipped:
					statusStatisticMap[8] += uint32(v.OrderID)
				case globalkey.AfterSaleStatusRejected:
					statusStatisticMap[9] += uint32(v.OrderID)
				case globalkey.AfterSaleStatusClosed, globalkey.AfterSaleStatusTimeouted:
					statusStatisticMap[10] += uint32(v.OrderID)
				}
				if v.Status != uint8(globalkey.AfterSaleStatusClosed) && v.Status != uint8(globalkey.AfterSaleStatusTimeouted) {
					total += v.OrderID
				}
			}
			statusStatisticMap[1] = uint32(total)
			resp.StatusStatisticMap = statusStatisticMap
		}
	}

	if !statusIsSet {
		statusIn := modelx.UniqueInterfaces(stati, 32)
		if len(statusIn) > 0 {
			statusMap["in"] = statusIn
		}
		if in.Status != nil {
			statusMap["equalTo"] = []any{*in.Status}
		}
		filterMap[model.AfterSaleRequestColumns.Status] = statusMap
	}

	if in.AfterSaleSn != nil && len(strings.TrimSpace(*in.AfterSaleSn)) > 0 {
		filterMap[model.AfterSaleRequestColumns.AfterSalesSN] = map[string][]any{
			"equalTo": {strings.TrimSpace(*in.AfterSaleSn)},
		}
	}
	if in.OrderSn != nil && len(strings.TrimSpace(*in.OrderSn)) > 0 {
		filterMap[model.AfterSaleRequestColumns.OrderSN] = map[string][]any{
			"equalTo": {*in.OrderSn},
		}
	}
	if in.ProductId != nil && *in.ProductId > 0 {
		filterMap[model.AfterSaleRequestColumns.ProductID] = map[string][]any{
			"equalTo": {*in.ProductId},
		}
	}
	if in.Mobile != nil && len(strings.TrimSpace(*in.Mobile)) > 0 {
		filterMap[model.AfterSaleRequestColumns.Mobile] = map[string][]any{
			"contain": {*in.Mobile},
		}
	}
	if in.AfterSaleType != nil && *in.AfterSaleType > 0 {
		filterMap[model.AfterSaleRequestColumns.AfterSaleType] = map[string][]any{
			"equalTo": {*in.AfterSaleType},
		}
	}

	var orderBy string
	if len(orderBys) > 0 {
		orderBy = strings.Join(orderBys, ",")
	} else {
		orderBy = model.AfterSaleRequestColumns.ID + " DESC"
	}
	res, count, err := l.svcCtx.AfterSaleRequest.GetList(l.ctx, model.M{
		"page":     page,
		"pageSize": pageSize,
		"orderBy":  orderBy,
	}, withCount, filterMap)
	if err != nil {
		return nil, errorhandler.DefaultRepositoryError(l.Logger, err, in)
	}

	if restricted {
		count = preCount
	}
	resp.Total = uint64(count)

	if len(res) > 0 {
		var rids []any
		var oids []any
		for _, v := range res {
			rids = append(rids, v.ID)
			oids = append(oids, v.OrderID)
		}

		idMediaMap := make(map[uint64][]*order.MediaInfo)
		if in.WithMedia != nil && *in.WithMedia > 0 {
			subFilterMap := make(map[string]map[string][]any)
			subFilterMap[model.AttachmentRelationshipColumns.ObjectID] = map[string][]any{
				"in": rids,
			}
			subFilterMap[model.AttachmentRelationshipColumns.ObjectType] = map[string][]any{
				"equalTo": {globalkey.AttachmentLogTypeAfterSale},
			}
			list, _, err := l.svcCtx.AfterSaleRequest.GetMedia(l.ctx, model.M{}, -1, subFilterMap)
			if err != nil {
				return nil, errorhandler.DefaultRepositoryError(l.Logger, err, in)
			}

			if len(list) > 0 {
				for _, v := range list {
					idMediaMap[v.ObjectID] = append(idMediaMap[v.ObjectID], &order.MediaInfo{
						Uid:       &v.RelationshipID,
						Id:        pointy.GetPointer(strconv.FormatUint(v.AttachmentID, 10)),
						Thumbnail: pointy.GetPointer(uint32(v.AttachmentThumbnail)),
						Order:     pointy.GetPointer(uint32(v.AttachmentOrder)),
						Uri:       &v.AttachmentImageSource,
						Url:       &v.AttachmentImageURL,
						AltText:   &v.AttachmentImageAlt,
						MetaData:  &v.AttachmentImageMeta,
					})
				}
			}
		}

		idPaymentMap := make(map[uint64][]*order.OrderPaymentInfo)
		if in.WithPayment != nil && *in.WithPayment > 0 {
			subFilterMap := make(map[string]map[string][]any)
			subFilterMap[model.OrderPaymentColumns.OrderID] = map[string][]any{
				"in": oids,
			}
			list, _, err := l.svcCtx.Order.GetPaymentList(l.ctx, model.M{}, -1, subFilterMap)
			if err != nil {
				return nil, errorhandler.DefaultRepositoryError(l.Logger, err, in)
			}

			if len(list) > 0 {
				for _, v := range list {
					idPaymentMap[v.OrderID] = append(idPaymentMap[v.OrderID], &order.OrderPaymentInfo{
						Id:      &v.OrderPaymentID,
						OrderId: &v.OrderID,
						No:      &v.No,
						Amount:  pointy.GetPointer(moneyx.FormatAmount(int64(v.Amount))),
						Type:    pointy.GetPointer(uint32(v.Type)),
						Name:    &v.Name,
						Code:    &v.Code,
						Status:  pointy.GetPointer(uint32(v.Status)),
						PaidAt:  pointy.GetPointer(modelx.FormatNullDotTime(v.PaidAt, "")),
					})
				}
			}
		}

		idAddressMap := make(map[uint64][]*order.OrderAddressInfo)
		if in.WithAddress != nil && *in.WithAddress > 0 {
			subFilterMap := make(map[string]map[string][]any)
			subFilterMap[model.OrderAddressColumns.OrderID] = map[string][]any{
				"in": oids,
			}
			list, _, err := l.svcCtx.Order.GetAddressList(l.ctx, model.M{}, -1, subFilterMap)
			if err != nil {
				return nil, errorhandler.DefaultRepositoryError(l.Logger, err, in)
			}

			if len(list) > 0 {
				for _, v := range list {
					idAddressMap[v.OrderID] = append(idAddressMap[v.OrderID], &order.OrderAddressInfo{
						Id:         &v.OrderAddressID,
						OrderId:    &v.OrderID,
						UserId:     &v.UserID,
						Consignee:  &v.Consignee,
						Mobile:     &v.Mobile,
						Province:   &v.Province,
						City:       &v.City,
						District:   &v.District,
						Street:     &v.Street,
						Address:    &v.DetailedAddress,
						PostalCode: &v.PostalCode,
						RegionCode: &v.RegionCode,
						Label:      &v.Label,
						Status:     pointy.GetPointer(uint32(v.Status)),
					})
				}
			}
		}
		for _, v := range res {
			var address []*order.OrderAddressInfo
			var media []*order.MediaInfo
			var payments []*order.OrderPaymentInfo
			if as, ok := idAddressMap[v.OrderID]; ok {
				address = as[:]
			}
			if ms, ok := idMediaMap[v.ID]; ok {
				media = ms[:]
			}
			if ps, ok := idPaymentMap[v.OrderID]; ok {
				payments = ps[:]
			}
			resp.List = append(resp.List, &order.AfterSaleInfo{
				Id:               &v.ID,
				AfterSaleSn:      &v.AfterSalesSN,
				OrderId:          &v.OrderID,
				OrderItemId:      &v.OrderItemID,
				OrderSn:          &v.OrderSN,
				ProductId:        &v.ProductID,
				ProductCode:      &v.ProductCode,
				ProductSkuId:     &v.ProductSkuID,
				ProductSku:       &v.ProductSku,
				SkuThumbUrl:      &v.SkuImageURL,
				ProductSkuCode:   &v.ProductSkuCode,
				ProductTitle:     &v.ProductTitle,
				ProductPrice:     &v.ProductPrice,
				Quantity:         pointy.GetPointer(uint32(v.Quantity)),
				UserId:           &v.UserID,
				NickName:         &v.NickName,
				Mobile:           &v.Mobile,
				AfterSaleType:    pointy.GetPointer(uint32(v.AfterSaleType)),
				RefundType:       pointy.GetPointer(uint32(v.RefundType)),
				ReturnType:       pointy.GetPointer(uint32(v.ReturnType)),
				RefundAmount:     pointy.GetPointer(moneyx.FormatAmount(int64(v.RefundAmount))),
				RefundDetails:    pointy.GetPointer(modelx.FormatNullDotString(v.RefundDetails)),
				Remark:           pointy.GetPointer(modelx.FormatNullDotString(v.Remark)),
				ExpressSn:        &v.ExpressSN,
				ReasonForRefusal: &v.ReasonForRefusal,
				Status:           pointy.GetPointer(uint32(v.Status)),
				ProcessTime:      pointy.GetPointer(modelx.FormatNullDotTime(v.ProcessTime, "")),
				CreatedAt:        pointy.GetPointer(modelx.FormatTime(v.CreatedAt, "")),
				UpdatedAt:        pointy.GetPointer(modelx.FormatTime(v.UpdatedAt, "")),
				EndedAt:          pointy.GetPointer(modelx.FormatNullDotTime(v.EndedAt, "")),
				DeletedAt:        pointy.GetPointer(modelx.FormatNullDotTime(v.DeletedAt, "")),
				Addresses:        address,
				Media:            media,
				Payment:          payments,
			})
		}
	}

	return resp, nil
}
